package org.crystalrange.documents.web;

import java.util.Date;
import java.util.List;
import java.util.Set;

import org.apache.commons.io.IOUtils;
import org.crystalrange.BaseController;
import org.crystalrange.documents.model.Document;
import org.crystalrange.documents.model.DocumentLockedHistory;
import org.crystalrange.documents.model.DocumentVersion;
import org.crystalrange.documents.model.DocumentVersionFile;
import org.crystalrange.documents.service.DocumentService;
import org.crystalrange.files.model.File;
import org.crystalrange.files.service.FileService;
import org.crystalrange.files.service.FileTypeService;
import org.crystalrange.model.User;
import org.crystalrange.service.UserService;
import org.springframework.security.core.context.SecurityContextHolder;
import org.zkoss.util.media.Media;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.UploadEvent;
import org.zkoss.zul.Filedownload;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Menuitem;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Toolbarbutton;
import org.zkoss.zul.Window;

import com.googlecode.genericdao.search.Search;

public class DocumentListController extends BaseController {

	protected DocumentService documentService;
	protected Document selectedDocument;
	protected List<Document> documents;
	protected Listbox listboxDocument;
	protected Search searchDocument;
	private UserService userService;
	private FileService fileService;
	private FileTypeService fileTypeService;
	private File uploadedFile;
	protected Menuitem menuitemDocumentLock;
	protected Toolbarbutton toolbarbuttonDocumentLock;
	
	public boolean getIsDocumentSelected() {
		return this.selectedDocument == null;
	}
	
	public boolean getIsDocumentLocked() {
		if (this.selectedDocument != null) {
			if (this.selectedDocument.getLockedBy() != null) {
				String username = SecurityContextHolder.getContext().getAuthentication().getName();
				User currentUser = this.userService.findByUsername(username);
				if (this.selectedDocument.getLockedBy().getUsername().equals(currentUser.getUsername())) {
					return false;
				}
			}
		}
		return true;
	}
	
	public boolean getIsDocumentLock() {
		if (this.selectedDocument != null) {
			if (this.selectedDocument.getLockedBy() != null) {
				this.menuitemDocumentLock.setLabel("Unlock");
				this.toolbarbuttonDocumentLock.setLabel("Unlock");
				String username = SecurityContextHolder.getContext().getAuthentication().getName();
				User currentUser = this.userService.findByUsername(username);
				if (this.selectedDocument.getLockedBy().getUsername().equals(currentUser.getUsername())) {
					return false;
				}
				return true;
			}
			this.menuitemDocumentLock.setLabel("Lock");
			this.toolbarbuttonDocumentLock.setLabel("Lock");
			return false;
		}
		this.menuitemDocumentLock.setLabel("Lock");
		this.toolbarbuttonDocumentLock.setLabel("Lock");
		return true;
	}
	
	public DocumentService getDocumentService() {
		return documentService;
	}

	public void setDocumentService(DocumentService documentService) {
		this.documentService = documentService;
	}

	public Document getSelectedDocument() {
		return selectedDocument;
	}

	public void setSelectedDocument(Document selectedDocument) {
		this.selectedDocument = selectedDocument;
	}

	public List<Document> getDocuments() {
		return documents;
	}

	public void setDocuments(List<Document> documents) {
		this.documents = documents;
	}
	
	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	
	public FileService getFileService() {
		return fileService;
	}

	public void setFileService(FileService fileService) {
		this.fileService = fileService;
	}

	public FileTypeService getFileTypeService() {
		return fileTypeService;
	}

	public void setFileTypeService(FileTypeService fileTypeService) {
		this.fileTypeService = fileTypeService;
	}
	
	public File getUploadedFile() {
		return uploadedFile;
	}

	public void setUploadedFile(File uploadedFile) {
		this.uploadedFile = uploadedFile;
	}
	
	public void onClick$toolbarbuttonDocumentCreate(Event event) throws Exception {
		this.documentCreate();
	}

	public void onClick$menuitemDocumentCreate(Event event) throws Exception {
		this.documentCreate();
	}

	public void onClick$toolbarbuttonDocumentEdit(Event event) throws Exception {
		this.documentEdit();
	}

	public void onClick$menuitemDocumentEdit(Event event) throws Exception {
		this.documentEdit();
	}

	public void onClick$toolbarbuttonDocumentDelete(Event event) throws Exception {
		this.documentDelete();
	}

	public void onClick$menuitemDocumentDelete(Event event) throws Exception {
		this.documentDelete();
	}

	public void onClick$toolbarbuttonDocumentSearch(Event event) throws Exception {
		this.documentSearch();
	}

	public void onClick$menuitemDocumentSearch(Event event) throws Exception {
		this.documentSearch();
	}

	public void onClick$toolbarbuttonDocumentRefresh(Event event) throws Exception {
		this.documentRefresh();
	}

	public void onClick$menuitemDocumentRefresh(Event event) throws Exception {
		this.documentRefresh();
	}
	
	public void onClick$toolbarbuttonDocumentLock(Event event) throws Exception {
		this.documentLock();
	}

	public void onClick$menuitemDocumentLock(Event event) throws Exception {
		this.documentLock();
	}
	
	public void onClick$toolbarbuttonDocumentCheckOut(Event event) throws Exception {
		this.documentCheckOut();
	}

	public void onClick$menuitemDocumentCheckOut(Event event) throws Exception {
		this.documentCheckOut();
	}
	
	public void onUpload$toolbarbuttonDocumentCheckIn(UploadEvent event) throws Exception {
		this.documentUpload(event);
	}

	public void onUpload$menuitemDocumentCheckIn(UploadEvent event) throws Exception {
		this.documentUpload(event);
	}
	
	public void onClick$toolbarbuttonDocumentLockedHistory(Event event) throws Exception {
		this.documentLockedHistory();
	}

	public void onClick$menuitemDocumentLockedHistory(Event event) throws Exception {
		this.documentLockedHistory();
	}

	@Override
	public void doAfterCompose(Component component) throws Exception {
		super.doAfterCompose(component);
		this.searchDocument = new Search(Document.class);
		this.searchDocument.setMaxResults(100);
		this.searchDocument.addFetch("createdBy");
		this.documents = this.documentService.search(this.searchDocument);
		component.setAttribute("controller", this);
	}
	

	private void documentCreate() throws Exception {
		this.execution.sendRedirect("~./zul/html/document.zul");
	}

	private void documentEdit() throws Exception {
		this.execution.sendRedirect("~./zul/html/document.zul?Id=" + this.selectedDocument.getId().toString());
	}

	private void documentDelete() throws Exception {
		Set<Listitem> selectedItems = this.listboxDocument.getSelectedItems();

		if (selectedItems.size() > 0) {
			if (Messagebox.YES == Messagebox.show("Delete these records?",
					"Delete?", Messagebox.YES | Messagebox.NO,
					Messagebox.QUESTION)) {
				for (Listitem selectedItem : selectedItems) {
					Document document = (Document) selectedItem.getValue();
					this.documentService.remove(document);
				}
				this.selectedDocument = null;
			}
		} else {
			this.message.setText("Please select at least one item!");
			this.message.setIcon("/img/exclamation.png");
		}
		this.documents = this.documentService.search(this.searchDocument);
		this.binder.loadAll();
	}

	private void documentSearch() throws Exception {
		this.execution.setAttribute("searchDocument", this.searchDocument);

		Window window = (Window) this.execution.createComponents("~./zul/html/documentSearch.zul", null, null);
		window.setParent(self);
		window.doModal();

		if (this.execution.getAttribute("result") == "ok") {
			this.searchDocument = (Search) this.execution
					.getAttribute("searchDocument");
		}

		this.documents = this.documentService.search(this.searchDocument);
		this.binder.loadAll();
	}

	private void documentRefresh() throws Exception {
		this.documents = this.documentService.search(this.searchDocument);
		this.binder.loadAll();
	}
	
	private void documentLock() throws Exception {
		String username = SecurityContextHolder.getContext().getAuthentication().getName();
		User currentUser = this.userService.findByUsername(username);
		
		if (this.selectedDocument.getLockedBy() != null) {
			this.selectedDocument.setLockedBy(null);
			
			for (DocumentLockedHistory documentLockedHistory : this.selectedDocument.getDocumentLockedHistorys()) {
				if (documentLockedHistory.getCheckOutDate() != null && documentLockedHistory.getCheckInDate() == null) {
					documentLockedHistory.setCheckInDate(new Date());
				}
			}
			this.message.setText("Document was unlocked.");
            this.message.setIcon("/img/information.png");
		} else {
			this.selectedDocument.setLockedBy(currentUser);
			
			DocumentLockedHistory documentLocked = new DocumentLockedHistory();
			documentLocked.setLockedBy(currentUser);
			documentLocked.setCheckOutDate(new Date());
			documentLocked.setDocument(this.selectedDocument);
			this.selectedDocument.getDocumentLockedHistorys().add(documentLocked);
			this.message.setText("Document was locked.");
            this.message.setIcon("/img/information.png");
		}
		this.documentService.save(this.selectedDocument);
		this.binder.loadAll();
	}
	
	private void documentCheckOut() throws Exception {
		if (!this.selectedDocument.getDocumentVersions().isEmpty()) {
			Long major = null;
			Long minor = null;
			for (DocumentVersion documentVersion : this.selectedDocument.getDocumentVersions()) {
				if (major == null || minor == null) {
					major = documentVersion.getMajor();
					minor = documentVersion.getMinor();
				}
				if ((documentVersion.getMajor() > major) || (documentVersion.getMajor() >= major && documentVersion.getMinor() > minor)) {
						major = documentVersion.getMajor();
						minor = documentVersion.getMinor();
				}
			}
			
			for (DocumentVersion documentVersion : this.selectedDocument.getDocumentVersions()) {
				if (documentVersion.getMajor().equals(major) && documentVersion.getMinor().equals(minor)) {
					if (!documentVersion.getDocumentVersionFiles().isEmpty()) {
						for (DocumentVersionFile documentVersionFile : documentVersion.getDocumentVersionFiles()) {
							if (documentVersionFile.getDefaultFile() != null) {
								if (documentVersionFile.getFile() != null) {
									Filedownload.save(
					    				documentVersionFile.getFile().getContent(), 
					    				documentVersionFile.getFile().getContentType(), 
					    				documentVersionFile.getFile().getName());
				    			
					    		} else {
					    			this.message.setText("There is no file to download!");
					                this.message.setIcon("/img/exclamation.png");
					            }
							}
						}
					} else {
						this.message.setText("For head document version, is no files to downoload!");
		                this.message.setIcon("/img/exclamation.png");
					}
				}
			}
		} else {
			this.message.setText("Document is empty!");
            this.message.setIcon("/img/exclamation.png");
		}
		this.binder.loadAll();
	}
	
	private void documentUpload(UploadEvent event) throws Exception {
		this.fileUpload(event);
		if (this.uploadedFile.getFileType() != null) {
			this.documentCheckIn();	
		}
		this.binder.loadAll();
	}
	
	private void fileUpload(UploadEvent event) throws Exception {
	       
        Media media = (Media) event.getMedia();
        
        if (media != null) {
        	
        	String username = SecurityContextHolder.getContext()
    				.getAuthentication().getName();
    		User currentUser = this.userService.findByUsername(username);

    		byte[] content = IOUtils.toByteArray(media.getStreamData());

    		this.uploadedFile = new File();
    		this.uploadedFile.setCreatedBy(currentUser);
    		this.uploadedFile.setCreatedDate(new Date());
    		this.uploadedFile.setContentType(media.getContentType());
    		this.uploadedFile.setName(media.getName());
    		this.uploadedFile.setContent(content);
    		this.uploadedFile.setSize((long) content.length);
    		int dotPos = this.uploadedFile.getName().lastIndexOf(".");
    		String extension = this.uploadedFile.getName().substring(dotPos);
    		Search search = new Search();
    		search.addFilterEqual("extension", extension);
    		
    		this.uploadedFile.setFileType(this.fileTypeService.searchUnique(search));
    		if (this.uploadedFile.getFileType() == null) {
    			this.message.setText("There is no defined file type for the extension '" + extension.toString() + "'.");
                this.message.setIcon("/img/exclamation.png");
    		}
        }
    }
	
	private void documentCheckIn() throws Exception {
		Long major = null;
		Long minor = null;
		if (!this.selectedDocument.getDocumentVersions().isEmpty()) {
			for (DocumentVersion documentVersion : this.selectedDocument.getDocumentVersions()) {
				if (major == null || minor == null) {
					major = documentVersion.getMajor();
					minor = documentVersion.getMinor();
				}
				if ((documentVersion.getMajor() > major) || (documentVersion.getMajor() >= major && documentVersion.getMinor() > minor)) {
						major = documentVersion.getMajor();
						minor = documentVersion.getMinor();
				}
			}
			minor = minor + 1;
		} else {
			major = (long) 1;
			minor = (long) 0;
		}
		
		String username = SecurityContextHolder.getContext().getAuthentication().getName();
		User currentUser = this.userService.findByUsername(username);
		
		DocumentVersion documentVersion = new DocumentVersion();
		documentVersion.setDocument(this.selectedDocument);
		documentVersion.setCreatedBy(currentUser);
		documentVersion.setCreatedDate(new Date());
		documentVersion.setMajor(major);
		documentVersion.setMinor(minor);
		documentVersion.setDescription("Document version: " + major.toString() + "." + minor.toString());
		
		DocumentVersionFile documentVersionFile = new DocumentVersionFile();
		documentVersionFile.setFile(this.uploadedFile);
		documentVersionFile.setDefaultFile("default");
		documentVersionFile.setDocumentVersion(documentVersion);
		this.execution.setAttribute("documentVersionFile", documentVersionFile);

		Window windowDocumentVersionFile = (Window) this.execution.createComponents("~./zul/html/documentVersionFile.zul", null, null);
		windowDocumentVersionFile.setParent(self);
		windowDocumentVersionFile.doModal();
		
		if (this.execution.getAttribute("result") == "ok") {
			documentVersion.getDocumentVersionFiles().add((DocumentVersionFile) this.execution.getAttribute("documentVersionFile"));
			this.execution.setAttribute("documentVersion", documentVersion);
		
			Window windowDocumentVersion = (Window) this.execution.createComponents("~./zul/html/documentVersion.zul", null, null);
			windowDocumentVersion.setParent(self);
			windowDocumentVersion.doModal();
			
			if (this.execution.getAttribute("result") == "ok") {
				this.selectedDocument.getDocumentVersions().add((DocumentVersion) this.execution.getAttribute("documentVersion"));
				if (this.uploadedFile.equals(documentVersionFile.getFile())) {
					this.fileService.save(this.uploadedFile);
					this.documentService.save(this.selectedDocument);
					this.message.setText("Document Version has been added.");
		            this.message.setIcon("/img/information.png");
				}
			}
		}
	}
	
	private void documentLockedHistory() throws Exception {
		this.execution.setAttribute("document", this.selectedDocument);

		Window window = (Window) this.execution.createComponents("~./zul/html/documentLockedHistoryList.zul", null, null);
		window.setParent(self);
		window.doModal();
	}
	
}
